package server;

import hibernateConfig.HibernateUtil;

import java.io.File;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.KeyPair;
import java.util.Date;
import org.hibernate.Session;
import utils.Terminal;
import encryptionEngines.MasterEngine;

public class SecureServer {

	private KeyPair keys;
	private Terminal console;
	private MasterEngine engine;
	private ServerSocket server;
	private ServerController svrController;
	private String storageDir = "Server\\Grupos";
	private Session session;
	private Runtime runtime;
	private Date initServer;
	private Date readyServer;
	private int h;

	public SecureServer(int port) throws Exception {
		initServer = new Date();
		session = HibernateUtil.getSessionFactory().openSession();
		console = new Terminal("Servidor");
		server = new ServerSocket(port);
		engine = new MasterEngine(2048);
		svrController = new ServerController(session);
		runtime = Runtime.getRuntime();
		init();
	}

	public void start() throws Exception {
		info();
		double p;
		while (true) {
			Socket client = server.accept();
			Thread c = new Thread(new ServerThread(client,
					new ServerController(HibernateUtil.getSessionFactory()
							.openSession()), h, keys, runtime));
			c.start();
			h++;
			p = (runtime.totalMemory() * 100) / runtime.maxMemory();
			if (p >= 70 || h > 1000) {
				console.info(">>>>>> Mejorando rendimiento...");
				console.info(">>>>>> Recolectando Objetos basura...");
				runtime.gc();
				h = 0;
			}
		}
	}

	private void init() throws Exception {
		File storage = new File(storageDir);
		if (!storage.exists()) {
			if (storage.mkdirs()) {
				console.info("Nuevo Servidor");
				console.info("Sistema de archivos creado");
				console.info("Generando claves...");
				keys = engine.generateRSAKeys();
				svrController.newServer(keys);
			} else
				console.error("Error al crear el sistema de archivos");
		} else {
			console.info("Sistema de archivos existente");
			keys = svrController.getServerKeys();
		}
		session.close();
	}

	public static void main(String[] args) throws Exception {
		SecureServer server = new SecureServer(5555);
		server.start();
	}

	private void info() {
		console.info("Procesadores: " + runtime.availableProcessors());
		console.info("Memoria Max: " + runtime.maxMemory() / (1024 * 1024)
				+ " MB");
		console.info("Memoria en uso: " + runtime.totalMemory() / (1024 * 1024)
				+ " MB");
		console.info("Memoria Libre: "
				+ (runtime.maxMemory() - runtime.totalMemory()) / (1024 * 1024)
				+ " MB");
		readyServer = new Date();
		console.info("Servidor Iniciado, escuchando...["
				+ diffSeconds(initServer, readyServer) + "]");
	}

	private double diffSeconds(Date strt, Date end) {
		double milis = end.getTime() - strt.getTime();
		return milis / 1000;
	}
}
